package com.example.interceptor;

import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;

public class InterceptorUtil {
    //为了加深记忆，我再弄一个classutil，重新敲一遍这些代码

    /**
     * 在方法参数中查找 请求对象
     *
     * @param params   请求参数
     * @param objClass 目标对象类型
     * @param <T>      返回对象类型
     * @return 返回分页对象
     */
    public static <T> T findObjectFromParams(Object params, Class<T> objClass) {
        if (params == null) {
            return null;
        }
        //params.getClass()是不是objClass的子类或者子接口,即参数对象是不是我们指定类型的子类
        if (objClass.isAssignableFrom(params.getClass())) {
            return (T) params;
        }

        if (params instanceof MapperMethod.ParamMap) {
            MapperMethod.ParamMap<Object> paramMap = (MapperMethod.ParamMap<Object>) params;
            for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                Object paramValue = entry.getValue();

                if (paramValue != null && objClass.isAssignableFrom(paramValue.getClass())) {
                    return (T) paramValue;
                }
            }
        }

        return null;
    }


    public static MappedStatement copyFromNewSql(MappedStatement ms,
                                                 BoundSql boundSql, String sql) {
        BoundSql newBoundSql = copyFromBoundSql(ms, boundSql, sql);

        return copyFromMappedStatement(ms, new BoundSqlSqlSource(newBoundSql));
    }

    /*
    由于copyFromMappedStatement builder里面需要sqlsource参数，boundsql不集成他，所以为了boundsql，
    新建个类集成sqlsource，传递给builder，然后到builder里面的mappedstatement里面的sqlsource，
    就能getboundsql了
     */
    private static class BoundSqlSqlSource implements SqlSource {
        BoundSql boundSql;

        public BoundSqlSqlSource(BoundSql boundSql) {
            this.boundSql = boundSql;
        }

        @Override
        public BoundSql getBoundSql(Object parameterObject) {
            return boundSql;
        }
    }

    public static int quertTotal(MappedStatement mappedStatement, BoundSql boundSql) {
        try {
            Connection connection = mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection();
            String countSql = "select count(*) from (" +boundSql.getSql()+ ") a";
            PreparedStatement countStmt = connection.prepareStatement(countSql);
            /*
            ParameterHandler需要我们new出来，因为metaobject属性里面没有这个，只有statementhandler里面有
            自己new boundsql 需要注意细节，毕竟不熟悉这个类,可能需要new出boundsql
             */
            BoundSql countBoundSql = copyFromBoundSql(mappedStatement,boundSql,countSql);
            ParameterHandler parameterHandler =
                    new DefaultParameterHandler(mappedStatement, boundSql.getParameterObject(), countBoundSql);
            parameterHandler.setParameters(countStmt);
            ResultSet rs = countStmt.executeQuery();
            if (rs.next())
                return rs.getInt(1);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /*
    项目组中使用的，不知道有什么用,成功了之后在删除试试
     */
    private static BoundSql copyFromBoundSql(MappedStatement ms, BoundSql boundSql,
                                             String sql) {
        BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject());
        for (ParameterMapping mapping : boundSql.getParameterMappings()) {
            String prop = mapping.getProperty();
            //如果you额外的参数，不知道什么时候会有额外的参数
            if (boundSql.hasAdditionalParameter(prop)) {
                newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));
            }
        }
        return newBoundSql;
    }
    /*
    和上面功能一样，一个是拷贝mappedstatement，一个是拷贝boundsql
     */
    private static MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());

        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) {
            StringBuilder keyProperties = new StringBuilder();
            for (String keyProperty : ms.getKeyProperties()) {
                keyProperties.append(keyProperty).append(",");
            }
            keyProperties.delete(keyProperties.length() - 1, keyProperties.length());
            builder.keyProperty(keyProperties.toString());
        }

        builder.timeout(ms.getTimeout());

        builder.parameterMap(ms.getParameterMap());

        builder.resultMaps(ms.getResultMaps());
        builder.resultSetType(ms.getResultSetType());

        builder.cache(ms.getCache());
        builder.flushCacheRequired(ms.isFlushCacheRequired());
        builder.useCache(ms.isUseCache());

        return builder.build();
    }
}
